home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Magazine
/
Online
/
httpproxy
/
src
/
httpdelete.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-20
|
17KB
|
613 lines
/*(( "Header" */
/*
* $Id: httpdelete.c,v 1.5 1996/08/12 03:33:36 mshopf Exp mshopf $
*
* (c) 1995-96 Matthias Hopf
*
* Invald File Deleter for httpproxy.
*
* This utility recursively deletes all invalid cache files and
* directory structures.
* When httpproxy is running it will inform it about cache file removals.
* (not yet implemented and no more needed).
*/
/*
* $Log: httpdelete.c,v $
* Revision 1.5 1996/08/12 03:33:36 mshopf
* deleting strange (7) files.
*
* Revision 1.4 1996/08/11 22:25:15 mshopf
* reworked debug messages.
*
* Revision 1.3 1996/07/17 16:42:42 mshopf
* support for new cache system.
*
* Revision 1.2 1996/04/26 05:18:25 mshopf
* logfile format, option priority.
* V0.13 alpha 5 fix.
*
* Revision 1.1 1996/04/16 04:39:29 mshopf
* Initial revision
*
*/
/*)) */
/*(( "Logfile Format" */
/* Format of the log file: */
/*
* LogFile ::= { LogEntry '\n' }*
* LogEntry ::= File | Directory | Error | Warn | Special
* Special ::= '*' DescriptiveText
* Error ::= '#' DescriptiveText
* Warn ::= '+' DescriptiveText
* File ::= ' ' Name
* Directory ::= ' ' Name ' (dir)'
* Name ::= { alphanummeric | '@' | '_' }*
* DescriptiveText ::= { printable | ' ' }*
*/
/*)) */
/*(( "Includes & Konstanten" */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <exec/exec.h>
#include <dos.h>
#include <dos/exall.h>
#include <dos/datetime.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include "httpproxy.h"
#include "cache.h"
#define MAX_DEPTH 20 /* Maximum recursion depth +1 (note that WorkData[0] is reserved) */
#define DEFAULT_EXALLBUFSIZE 2048 /* default number of ExAll() examination buffer bytes per recursion
* (may be less as additional info is stored here) */
#define DEFAULT_DELETETIME (60*24*60*60) /* default deletetime in seconds (two months here) */
#define MAX_DIRNAME 1024 /* Maximum Size of directory name */
/* The following macro is only here for historical reasons. It is not used anymore */
/* Note: this macro won't handle files older than aprox. 136 years correctly :-P */
/*
#define difftime(x,y) ((((long)(x)->ds_Days - (long)(y)->ds_Days) * 24L * 60L + \
((long)(x)->ds_Minute - (long)(y)->ds_Minute)) * 60L + \
((long)(x)->ds_Tick - (long)(y)->ds_Tick) / TICKS_PER_SECOND )
*/
/*)) */
/*(( "Global Variables" */
typedef struct {
BPTR DirLock;
short More;
short Needed; /* directory is needed, e.g. not empty */
struct ExAllControl *ExAllCtrl;
struct ExAllData *Buffer;
struct ExAllData *CurrentBuf;
} work_t;
long __oslibversion = 37;
#ifdef DEBUG
int DebugLevel = -1;
#endif
char *LogName = NULL;
FILE *LogStream = NULL;
BPTR CacheDirLock = NULL;
work_t WorkData [MAX_DEPTH]; /* Note: C ansi standard initializes this with NULL */
/* WorkData[0].DirLock is reserved for the initial working directory */
char StringDay [LEN_DATSTRING];
char StringTime [LEN_DATSTRING];
char StringDate [LEN_DATSTRING];
struct DateTime CurrentDT = { {0, 0, 0}, FORMAT_DOS, 0, StringDay, StringDate, StringTime };
struct DateStamp ValidDS;
int DeleteTime = DEFAULT_DELETETIME;
ULONG ExAllBufSize = DEFAULT_EXALLBUFSIZE;
int CheckOnly = 0;
long DelayTicks = 0;
/*)) */
/*(( "ExitAll (), Error ()" */
/* Close everything and return */
void ExitAll (int Ret)
{
work_t *W;
if (WorkData->DirLock)
CurrentDir (WorkData->DirLock);
for (W = & WorkData [1]; W < & WorkData [MAX_DEPTH]; W++)
{
if (W->ExAllCtrl)
FreeDosObject (DOS_EXALLCONTROL, W->ExAllCtrl);
W->ExAllCtrl = NULL; /* not needed as we exit immedeately */
if (W->DirLock)
UnLock (W->DirLock);
W->DirLock = NULL; /* but let's keep it consistent... */
if (W->Buffer)
FreeMem (W->Buffer, ExAllBufSize);
W->Buffer = NULL;
}
if (LogStream)
fclose (LogStream);
LogStream = NULL;
UnLock (CacheDirLock); /* may be already NULL */
CacheDirLock = NULL;
exit (Ret);
}
/* Print out error message and exit() */
void Error (char *Msg)
{
if (LogStream)
fprintf (LogStream, "# Error: %s\n", Msg);
fprintf (stderr, "Error: %s\n", Msg);
ExitAll (10);
}
/*)) */
/*(( "Init ()" */
/* Init all global variables, open logfile if any */
void Init (char *ProgName, char *LogName)
{
long CalcTime;
if (LogName)
{
if (! (LogStream = fopen (LogName, "w+")))
Error ("can't open logfile");
}
DateStamp (&CurrentDT.dat_Stamp);
DateToStr (&CurrentDT);
if (LogStream)
fprintf (LogStream, "* %s startup on %s, %s %s\n", ProgName, StringDay, StringDate, StringTime);
/* Could use the DateStamp entries, but I don't wanna rely on the entries being signed */
CalcTime = CurrentDT.dat_Stamp.ds_Tick - (DeleteTime % 60) * TICKS_PER_SECOND;
if (CalcTime < 0)
{
ValidDS.ds_Tick = CalcTime + 60 * TICKS_PER_SECOND;
CalcTime = -1;
}
else
{
ValidDS.ds_Tick = CalcTime;
CalcTime = 0;
}
CalcTime += CurrentDT.dat_Stamp.ds_Minute - (DeleteTime / 60) % (24 * 60);
if (CalcTime < 0)
{
ValidDS.ds_Minute = CalcTime + 24 * 60;
CalcTime = -1;
}
else
{
ValidDS.ds_Minute = CalcTime;
CalcTime = 0;
}
CalcTime += CurrentDT.dat_Stamp.ds_Days - DeleteTime / (24 * 60 * 60);
if (CalcTime < 0) /* kidding?!? */
Error ("invald time range");
ValidDS.ds_Days = CalcTime;
}
/*)) */
/*(( "ParseOpt ()" */
/* Parse options template */
/* <- CacheDirLock ggf. Lock auf CacheDir */
void ParseOpt (char *PrgName)
{
char *Template = "CACHEDIR=DIR/A,TIME/N,LOGFILE=LOG/K,EXBUFFERSIZE=EXBUF/K/N,CHECKONLY=CHECK/S,DELAY/K/N,PRIORITY=PRI/K/N";
long RetArray[] = { 0, 0, 0, 0, 0, 0, 0 };
struct RDArgs *Args;
if (! (Args = ReadArgs (Template, RetArray, NULL)))
{
fprintf (stderr, "%s\n"
"\tTIME: Spezifies minimum age in seconds before a file is removed.\n"
"\t Defaults to %d seconds.\n"
"\tCACHEDIR: Location of cache files to be scanned.\n"
"\tLOGFILE: Name of the logfile (none when omitted).\n"
"\tEXBUFFERSIZE: Size of the examination buffer (minimum is about 64 bytes).\n"
"\t Defaults to %d bytes.\n"
"\tCHECKONLY: Do not perform deletes, only write log entries.\n"
"\tDELAY: For use in server environments. Specifies the number of ticks\n"
"\t to be waited after each ExAll() call. Mostly usefull with not\n"
"\t too high values for EXBUFFERSIZE (use the default).\n"
"\tPRIORITY: Priority while running. The current priority won't be\n"
"\t changed when this option is not specified.\n"
"Check the docs for more information about httpproxy and its utilities.\n",
Template, DEFAULT_DELETETIME, DEFAULT_EXALLBUFSIZE);
ExitAll (10);
}
if (! (CacheDirLock = Lock ((char *) RetArray [0], ACCESS_READ))) /* CACHEDIR */
{
FreeArgs (Args);
Error ("can't lock cache directory");
}
if (RetArray [1]) /* TIME */
DeleteTime = * (long *) RetArray [1];
LogName = (char *) RetArray [2]; /* LOGFILE */
if (RetArray [3]) /* EXBUFFERSIZE */
ExAllBufSize = * (long *) RetArray[3];
CheckOnly = RetArray [4]; /* CHECKONLY */
if (RetArray [5]) /* DELAY */
DelayTicks = * (long *) RetArray [5];
if (RetArray [6]) /* PRIORITY */
SetTaskPri (FindTask (NULL), * (long *) RetArray [6]);
Init (PrgName, LogName);
FreeArgs (Args);
}
/*)) */
/*(( "GenerateDirName ()" */
/* Generate current workdir name into static buffer */
char *GenerateDirName (work_t *Working)
{
static char Name [MAX_DIRNAME];
char *N = Name;
work_t *W;
for (W = & WorkData [1]; W < Working; W++) /* Working is the current working directory */
{
strcpy (N, W->CurrentBuf->ed_Name);
N += strlen (N);
*N++ = '/';
}
*N = '\0';
return (Name);
}
/*)) */
/*(( "EnterDir ()" */
/* Shall we enter a named directory? */
int EnterDir (struct ExAllData *E)
{
if (CacheRemoveDir (E->ed_Name, FALSE) != 1)
return FALSE; /* skip special dirs */
return TRUE;
}
/*)) */
/*(( "FileValid ()" */
/* Check whether this is a valid cache entry file */
int FileValid (work_t *W, struct ExAllData *E)
{
if (CompareDates ((struct DateStamp *) & E->ed_Days, & ValidDS) <= 0)
return TRUE;
else
return FALSE;
}
/*)) */
/*(( "CheckFile ()" */
void CheckFile (work_t *W, struct ExAllData *E)
{
/* check type of cache file */
switch (CacheRemove (E->ed_Name, FALSE)) {
case 1: /* - standard file: check it */
if (FileValid (W, E))
{
W->Needed = TRUE;
return;
}
break;
case 2: /* directory management file */
case 4: /* no more existant */
case 5: /* cache related file */
return; /* ->nothing to do */
case 7: /* strange files to be deleted */
if (LogStream)
fprintf (LogStream, "+ file '%s%s' lost info file - deleting\n", GenerateDirName (W), E->ed_Name);
break;
case 3: /* stange file */
if (LogStream)
fprintf (LogStream, "# file '%s%s' is strange - skipping\n",
GenerateDirName (W), E->ed_Name);
W->Needed = TRUE; /* the dir is 'valid' as we may *not* remove it */
return;
case 6: /* special file */
W->Needed = TRUE;
return; /* not handled by httpdelete */
case 0: /* we *don't* do deletes here! */
default:
assert (0);
}
/* File is not valid, so it must be removed! */
if (CheckOnly)
{
if (LogStream)
fprintf (LogStream, " %s%s\n", GenerateDirName (W), E->ed_Name);
}
else
{
switch (CacheRemove (E->ed_Name, TRUE)) {
case 1: /* success: deleted file */
if (LogStream)
fprintf (LogStream, " %s%s\n", GenerateDirName (W), E->ed_Name);
break;
case 4: /* no more existing... */
break;
case 0: /* delete error */
if (LogStream)
{
char ErrMsg [128];
Fault (IoErr (), "", ErrMsg, 128);
fprintf (LogStream, "# file '%s%s' delete error: %s\n",
GenerateDirName (W), E->ed_Name, ErrMsg);
}
W->Needed = TRUE;
break;
default: /* all other cases should *not* get here... */
assert (0);
}
}
}
/*)) */
/*(( "CheckDir ()" */
/* Check directory for deleting it */
void CheckDir (work_t *Parent, struct ExAllData *E, int Needed)
{
if (Needed)
return;
else if (CheckOnly)
{
if (LogStream)
fprintf (LogStream, " %s%s (dir)\n", GenerateDirName (Parent), E->ed_Name);
}
else
{
switch (CacheRemoveDir (E->ed_Name, TRUE)) {
case 1:
if (LogStream)
fprintf (LogStream, " %s%s (dir)\n", GenerateDirName (Parent), E->ed_Name);
break;
case 0:
Parent->Needed = TRUE; /* We won't be able to delete the directory */
if (LogStream)
{
char ErrMsg [128];
Fault (IoErr (), "", ErrMsg, 128);
fprintf (LogStream, "# directory '%s%s' delete error: %s\n",
GenerateDirName (Parent), E->ed_Name, ErrMsg);
}
break;
case 2:
Parent->Needed = TRUE; /* We won't be able to delete the directory */
break;
default: /* special dirs should not be entered and thus not deleted! */
assert (0);
}
}
}
/*)) */
/*(( "DeleteLoop ()" */
/* Major Loop: Nonrekursive rekursive loop through a directory */
/* <- BeginLock will be freed! */
void DeleteLoop (BPTR BeginLock)
{
work_t *W = & WorkData [1];
struct ExAllData *E;
WorkData->CurrentBuf = NULL;
WorkData->DirLock = CurrentDir (BeginLock);
W->DirLock = BeginLock;
W->CurrentBuf = NULL; /* For subsequent calls */
W->More = FALSE;
W->Needed = TRUE; /* Don't delete main directory (wouldn't be needed due to special directories) */
while (W > WorkData) /* W[0] is reserved for the initial directory */
{
do
{
/* Main Outer Loop */
/* Check for Ctrl-C once a while (not every time...) */
if (SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
Error ("interrupted");
if (DelayTicks)
Delay (DelayTicks);
/* Allocate all necessary things */
if (! W->Buffer)
if (! (W->Buffer = AllocMem (ExAllBufSize, 0L)))
{
if (LogStream)
fprintf (LogStream, "Not enough memory - skipping");
break;
}
if (! W->ExAllCtrl)
{
if (! (W->ExAllCtrl = (struct ExAllControl *) AllocDosObject(DOS_EXALLCONTROL,NULL)))
{
if (LogStream)
fprintf (LogStream, "# can't alloc dosobject - skipping\n");
break;
}
W->ExAllCtrl->eac_LastKey = 0;
W->CurrentBuf = NULL;
}
/* Examine directory when needed */
if (W->CurrentBuf) /* Continue aborted directory */
E = W->CurrentBuf->ed_Next;
else /* start new examination */
{
W->More = ExAll (W->DirLock, W->Buffer, ExAllBufSize, ED_DATE, W->ExAllCtrl);
if ((! W->More) && (IoErr () != ERROR_NO_MORE_ENTRIES))
{
if (LogStream)
fprintf (LogStream, "# ExAll() Error: %d - skipping\n", IoErr());
FreeDosObject (DOS_EXALLCONTROL, W->ExAllCtrl); /* Remove eventually corrupt DosObject */
W->ExAllCtrl = NULL; /* (ExAllEnd is V39 only) */
break;
}
if (! W->ExAllCtrl->eac_Entries)
/* ExAll failed normally with no entries */
continue; /* ("More" is *usually* zero) */
E = W->Buffer;
}
W->CurrentBuf = NULL;
while (E)
{
/* Main Inner Loop */
if (E->ed_Type > 0) /* it is a directory */
{
if (! EnterDir (E))
W->Needed = TRUE; /* don't delete non-entered directories */
else
{
if (W >= & WorkData [MAX_DEPTH-1])
{
if (LogStream)
fprintf (LogStream, "# maximum depth reached, skipping\n");
}
else
{
/* Enter next directory level */
W->CurrentBuf = E;
W++;
W->CurrentBuf = NULL;
W->More = TRUE;
W->Needed = FALSE;
W->DirLock = Lock (E->ed_Name, ACCESS_READ);
CurrentDir (W->DirLock); /* in case it is 0, we're temporary on sys: */
if (! W->DirLock)
W->More = FALSE;
break;
}
}
}
else
CheckFile (W, E);
E = E->ed_Next;
}
} while (W->More);
if (W->ExAllCtrl)
W->ExAllCtrl->eac_LastKey = 0; /* for subsequent uses */
/* ExAllCtrl is not deallocated for speedup in subsequent uses */
/* go to higher directory level */
W--;
CurrentDir (W->DirLock);
UnLock (W [1] .DirLock);
W [1] .DirLock = NULL;
if (W [1] .Needed)
W->Needed = TRUE;
/* check directory (W is the parent directory) */
if (W->CurrentBuf)
CheckDir (W, W->CurrentBuf, W [1] .Needed);
}
}
/*)) */
/*(( "main ()" */
/* The main routine */
void main (int argc, char **argv)
{
BPTR LastDir, TestLock;
ParseOpt (argv [0]);
/* Test existance of CACHEDIRVALIDFILE */
LastDir = CurrentDir (CacheDirLock);
TestLock = Lock (CACHEDIRVALIDFILE, ACCESS_READ);
CurrentDir (LastDir);
if (! TestLock)
Error ("can't lock '" CACHEDIRVALIDFILE "' - seems to be the wrong directory!");
UnLock (TestLock);
TestLock = CacheDirLock;
CacheDirLock = NULL; /* CacheDirLock is unlocked by DeleteLoop */
DeleteLoop (TestLock);
ExitAll (0);
}
/*)) */
/*(( "assert()" */
#ifndef NDEBUG
void ASSERT (int x, const char *text, const char *file, const char *func, int line)
{
if (x)
return;
if (! text)
text = "unknown";
fprintf (stderr, "assertion (%s) failed in '%s' of '%s' on line %d\n", text, func, file, line);
ExitAll (20);
/*NOTREACHED*/
}
#endif /* NDEBUG */
/*)) */
/*(( "LogErr ()" */
/* We don't need LogErr -> dummy function */
void LogErr (request_t *Req, const char *Status, const char *Url, int ErrNo, const char *Reason, ...)
{
ASSERT (0, Reason, __FILE__, __FUNC__, 0);
}
/*)) */